home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / freeWAIS-sf-1.1 / ui / lisp-ui.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-04  |  10.0 KB  |  377 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  9.  
  10.  
  11.  
  12. /* This is a simple wais interface for lisp clients.
  13.  * It takes in lisp-y looking requests and sends out Z39.50 packets.
  14.  *
  15.  * -brewster 7/90
  16.  *
  17.  * Important functions:
  18.  *   display_search_response
  19.  *   main
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include "../ir/cdialect.h"
  25. #include "../ir/ui.h"
  26.  
  27. #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
  28. #define MAX_MESSAGE_LEN BUFSZ
  29. #define VERBOSE false /* true */
  30.  
  31. /****************************************************************
  32.  *
  33.  *         Function Name:  display_search_response
  34.  *
  35.  *
  36.  *     Purpose: displays the formatted list of documents in the form  
  37.  *               that the super-text-server would like to see. 
  38.  *
  39.  *     Returns: nothing.
  40.  *
  41.  *    Algorithm:   . ...
  42.  *
  43.  */
  44.  
  45.  
  46. /* modified from tracy shen's version in wutil.c
  47.  * displays a set of headlines.
  48.  */
  49. void
  50. display_search_response(response,database,server_name,service_name)
  51. SearchResponseAPDU *response;
  52. char *database;
  53. char *server_name;
  54. char *service_name;
  55. {
  56.   WAISSearchResponse  *info;
  57.   long k;
  58.   printf("(:query (");
  59.  
  60.   if ( response->DatabaseDiagnosticRecords != 0 ) {
  61.     info = response->DatabaseDiagnosticRecords;
  62.     if(info->DocHeaders != 0){
  63.       k =0;
  64.       while(info->DocHeaders[k] != 0 ){       
  65.     char doc_id[1000];
  66.     strncpy(doc_id,    info->DocHeaders[k]->DocumentID->bytes,
  67.         MINIMUM(info->DocHeaders[k]->DocumentID->size, 1000));
  68.     doc_id[MINIMUM(info->DocHeaders[k]->DocumentID->size, 1000 - 1)] 
  69.       = '\0';
  70.     printf("(:doc-id \"%s\" :document-length %ld :types (\"%s\") :database-name \"%s\" :server-name \"%s\" :score %ld :service \"%s\" :header \"",
  71.            doc_id,
  72.            info->DocHeaders[k]->DocumentLength,
  73.            (info->DocHeaders[k]->Types == NULL)?"TEXT":info->DocHeaders[k]->Types[0],
  74.            database,
  75.            server_name,
  76.            info->DocHeaders[k]->Score,
  77.            service_name
  78.            );
  79.     { char *header = trim_junk(info->DocHeaders[k]->Headline);
  80.       long i;
  81.       for(i=0; i < strlen(header); i++){
  82.         char ch = header[i];
  83.         if(ch == '"')
  84.           putc('\\', stdout);
  85.         putc(ch, stdout);
  86.       }
  87.     }
  88.     printf("\")");
  89.     k++;
  90.       }
  91.     }
  92.   }
  93.   printf(")\n:end t)\n");    /* finish it */
  94.   fflush(stdout);
  95. }
  96.  
  97.  
  98. /*******************
  99.  *     Parsing     *
  100.  *******************/
  101.  
  102. /* In a alist of keys and values,
  103.  * this finds the string value associated with a key.
  104.  * The way this is implemented is a kludge since it searches for
  105.  * the key with string search rather than making a list and
  106.  * searching down it.  This can error if a value contains a string version
  107.  * of the key.
  108.  * What we really need is list facilities.
  109.  *
  110.  * Side effects value.
  111.  * Returns 0 if it wins, 1 if there is no such slot, -1 if error.
  112.  */
  113.  
  114. /* these are states of the parser */
  115. #define BEFORE 1
  116. #define DURING 2
  117. #define QUOTE 5
  118.  
  119. long find_string_slot(source,key,value,value_size,delete_internal_quotes)
  120. char *source;
  121. char *key;
  122. char *value;
  123. long value_size;
  124. boolean delete_internal_quotes;
  125. {
  126.   char ch;
  127.   short state = BEFORE;
  128.   long position = 0;  /* position in value */
  129.   char *pos =strstr(source, key); /* address into source */
  130.  
  131.   value[0] = '\0';        /* initialize to nothing */
  132.  
  133.   if(NULL == pos)
  134.     return(1);
  135.  
  136.   for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
  137.     ch = *pos;
  138.     if((state == BEFORE) && (ch == '\"'))
  139.       state = DURING;
  140.     else if ((state == DURING) && (ch == '\\')){
  141.       state = QUOTE;    
  142.       if(!delete_internal_quotes){
  143.     value[position] = ch;
  144.     position++;
  145.     if(position >= value_size){
  146.       value[value_size - 1] = '\0';
  147.       return(-1);
  148.     }
  149.       }
  150.     }
  151.     else if ((state == DURING) && (ch == '"')){    
  152.       value[position] = '\0';
  153.       return(0);
  154.     }
  155.     else if ((state == QUOTE) || (state == DURING)){
  156.       if(state ==  QUOTE)
  157.     state = DURING;
  158.       value[position] = ch;
  159.       position++;
  160.       if(position >= value_size){
  161.     value[value_size - 1] = '\0';
  162.     return(-1);
  163.       }
  164.     }
  165.     /* otherwise we are still before the start of the value */
  166.   }
  167.   value[position] = '\0';
  168.   return(-1); /* error because we are in the middle of the string */
  169. }
  170.  
  171. /* reads a long int a file returns true if successful, false otherwise */
  172. long find_long_slot(source,key,answer)
  173. char *source;
  174. char *key;
  175. long *answer;
  176. {
  177.   char ch;
  178.   short state = BEFORE;
  179.   char *pos =strstr(source, key); /* address into source */
  180.   long count = 0;
  181.   boolean isNegative = false;
  182.   *answer = 0;
  183.  
  184.   if(NULL == pos)
  185.     return(1);
  186.  
  187.   for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
  188.     ch = *pos;
  189.     if (isdigit(ch)){
  190.       if(state == BEFORE){
  191.     state = DURING;
  192.       }
  193.       count++;
  194.       if(count == 12){
  195.     /* then we have an error in the file, 32 bit numbers can not be more
  196.        than 10 digits long */
  197.     return(-1);
  198.       }
  199.       *answer = *answer * 10 + (ch - '0');
  200.     }
  201.     else if (ch == '-') {
  202.       if (isNegative)
  203.     /* then we have an error since there should be only one - in a number */
  204.     return(-1);
  205.       if (state == BEFORE) {
  206.     /* we are ok since the - must come before any digits */
  207.     isNegative = true;
  208.     state = DURING;
  209.       }
  210.       else {
  211.     break;            /* we are done */
  212.       }
  213.     }
  214.     else if(!isspace(ch)){
  215.       /* then we have an error since it should be a digit or a space */
  216.       return(-1);
  217.     }
  218.     /* we do not have an digit */
  219.     else if(state == DURING){
  220.       break;            /* we are done */
  221.     }
  222.     /* otherwise we are still before the start */
  223.   }
  224.   if (isNegative)
  225.     *answer *= -1;
  226.   return(0);
  227. }
  228.  
  229.  
  230.  
  231. /************
  232.  *   MAIN   *
  233.  ************/
  234.  
  235. #define MAX_QUERY_SIZE 10000
  236. #define MAX_NAME_SIZE 1000
  237. void main()
  238. {
  239.   char query[MAX_QUERY_SIZE + 1];
  240.   char request_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
  241.   char response_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
  242.   long request_buffer_length;    /* how of the request is left */
  243.   SearchResponseAPDU  *query_response;
  244.   SearchResponseAPDU  *retrieval_response;
  245.   char service[MAX_NAME_SIZE + 1];
  246.   char database[MAX_NAME_SIZE + 1];
  247.   char server_name[MAX_NAME_SIZE + 1];
  248.   char type[MAX_NAME_SIZE + 1];
  249.  
  250.   server_name[0] = '\0';    /* null it out */
  251.   database[0] = '\0';        /* null it out */
  252.   service[0] = '\0';        /* null it out */
  253.  
  254.   while(TRUE){
  255.     /* continue to search until the user gets tired */
  256.  
  257.     fgets(query, MAX_QUERY_SIZE, stdin);
  258.     if(NULL != strstr(query, ":fill-in") ||
  259.        NULL != strstr(query, ":query")){
  260.       /* then we have a fill-in or query. 
  261.      extract the common fields */
  262.  
  263.       if(0 > find_string_slot(query, ":database", database,
  264.                   MAX_NAME_SIZE, false)){
  265.     panic("Could not read the database from query %s", query);
  266.       }
  267.       if(0 > find_string_slot(query, ":server", server_name,
  268.                   MAX_NAME_SIZE, false)){
  269.     panic("Could not read the host from query %s", query);
  270.       }
  271.       if(0 > find_string_slot(query, ":service", service,
  272.                   MAX_NAME_SIZE, false)){
  273.     panic("Could not read the service from query %s", query);
  274.       }
  275.     }
  276.  
  277.     if(NULL != strstr(query, ":fill-in")){
  278.       /* then we have a fill-in request */
  279.       long count;
  280.       long document_length;
  281.       char doc_id[MAX_NAME_SIZE + 1];
  282.       any doc_id_any;
  283.       if(0 != find_string_slot(query, ":doc-id", doc_id,
  284.                    MAX_NAME_SIZE, false)){
  285.     panic("Could not read the doc-id from request %s", query);
  286.       }
  287.       doc_id_any.bytes = doc_id;
  288.       doc_id_any.size = strlen(doc_id);
  289.  
  290.       if(0 != find_long_slot(query, ":document-length", &document_length)){
  291.     panic("Could not read the document length from doc_id %s", query);
  292.       }
  293.       if(0 != find_string_slot(query, ":type", type,
  294.                    MAX_NAME_SIZE, false)){
  295.     panic("Could not read the type from request %s", query);
  296.       }
  297.  
  298.       printf("(:fill-in (:text \""); /* start the reply */
  299.       for(count = 0; 
  300.       count * CHARS_PER_PAGE < document_length;
  301.       count++){
  302.     request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  303.     if(NULL ==
  304.        generate_retrieval_apdu(request_message + HEADER_LENGTH,
  305.                    &request_buffer_length, 
  306.                    &doc_id_any,
  307.                    CT_byte,
  308.                    count * CHARS_PER_PAGE,
  309.                    MINIMUM((count + 1) * CHARS_PER_PAGE, 
  310.                        document_length),
  311.                    type,
  312.                    database
  313.                    ))
  314.       panic("query was too large");
  315.     
  316.     if(0 ==
  317.        interpret_message(request_message, 
  318.                  MAX_MESSAGE_LEN - request_buffer_length, 
  319.                  response_message,
  320.                  MAX_MESSAGE_LEN,
  321.                  server_name, 
  322.                  service, 
  323.                  VERBOSE
  324.                  ))
  325.       panic("return message too large");
  326.  
  327.     readSearchResponseAPDU(&retrieval_response, 
  328.                    response_message + HEADER_LENGTH);
  329.     if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text)
  330.       panic("No text was returned");
  331.  
  332.     display_text_record_completely
  333.       (((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], true);
  334.       }
  335.       printf("\")\n:end t)\n");    /* finish the text */
  336.       fflush(stdout);
  337.     }
  338.     else if(NULL != strstr(query, ":query")){
  339.       /* then we have a query */
  340.       char seed_words[MAX_QUERY_SIZE + 1];
  341.       if(0 != find_string_slot(query, ":seed-words", seed_words,
  342.                    MAX_QUERY_SIZE, false)){
  343.     panic("Could not read the seed words from query %s", query);
  344.       }
  345.       request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  346.       if(NULL ==
  347.      generate_search_apdu(request_message + HEADER_LENGTH, 
  348.                   &request_buffer_length, 
  349.                   seed_words, database, NULL))
  350.     panic("Query was too large");
  351.      
  352.       if(0 ==
  353.      interpret_message(request_message,
  354.                MAX_MESSAGE_LEN - request_buffer_length, 
  355.                response_message,
  356.                MAX_MESSAGE_LEN,
  357.                server_name, 
  358.                service,
  359.                VERBOSE
  360.                ))
  361.     panic("return message too large");
  362.  
  363.       readSearchResponseAPDU(&query_response, 
  364.                  response_message + HEADER_LENGTH);
  365.       display_search_response(query_response, database, server_name,
  366.                   service);
  367.     }
  368.     else
  369.       panic("Dont know how to handle query %s\n", query);
  370.   }
  371. }
  372.     
  373.   
  374. /* sample
  375. (:query :seed-words ("food") :database "/u/kahle/wais-index-irn8/foo" :server "gandalf" :service "8000")
  376. */
  377.